/*
 * JANN - a Java toolkit for creating arbitrary Artificial Neural Networks.
 * 
 * Copyright (c) 2009 Matthijs Snel
 * 
 * This program is free software: you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with this program.  If not, see <http://www.gnu.org/licenses/>.
 */
package net.jann.ui;

import java.awt.Color;
import java.awt.geom.Point2D;
import java.text.NumberFormat;
import java.util.ArrayList;
import java.util.List;
import java.util.Observable;
import java.util.Observer;

import net.jann.Neuron;

import org.jhotdraw.draw.AttributeKeys;
import org.jhotdraw.draw.TextAreaFigure;
import org.jhotdraw.draw.TextFigure;

public class NeuronFigure extends TextAreaFigure implements Observer {
	
	public final static int DEFAULT_WIDTH = 50,
						DEFAULT_HEIGHT = 50;
	
	private boolean highlighted = false,
					weightDisplayed = false;

	protected Neuron model;
	protected List<LinkFigure> outgoing, incoming;
	protected NumberFormat format;
	
	private static final long serialVersionUID = -5412009580440450369L;

	public NeuronFigure() {
		this( new Neuron() );		
	}
	
	public NeuronFigure( double x, double y ) {
		this( new Neuron() );
		setStartPoint(x,y);
	}
	
	public NeuronFigure( Neuron model ) {
		super();
		incoming = new ArrayList<LinkFigure>();
		outgoing = new ArrayList<LinkFigure>();
		initNumberFormat();
		setModel( model );
	}
	
	public void addOutputLink( LinkFigure f ) {
		outgoing.add(f);
	}
	
	public void addInputLink( LinkFigure f ) {
		incoming.add(f);
	}
	
	public void displayWeight( boolean display ) {
		if ( weightDisplayed == display )
			return;
		weightDisplayed = display;
		super.setText( display ? getText() + "\n" + format.format(model.getWeight())
						: format.format(model.getActivation()));
	}
	
	public List<LinkFigure> getIncoming() {
		return incoming;
	}
	
	public List<LinkFigure> getOutgoing() {
		return outgoing;
	}
	
	public Neuron getModel() {
		return model;
	}
	
	public boolean isHighlighted() {
		return highlighted;
	}

	public void setHighlighted(boolean highlighted) {
		if ( this.highlighted == highlighted )
			return;
		this.highlighted = highlighted;
		if ( highlighted ) {
			AttributeKeys.STROKE_COLOR.set(this, Color.red);
			displayWeight(true);
		} else {
			AttributeKeys.STROKE_COLOR.set(this, Color.black);
			displayWeight(false);
		}
	}
	
	public boolean removeInputLink( LinkFigure l ) {
		return incoming.remove(l);
	}
	
	public boolean removeOutputLink( LinkFigure l ) {
		return outgoing.remove(l);
	}
	
	public void setModel( Neuron model ) {
		if ( this.model != null )
			this.model.deleteObserver(this);
		this.model = model;
		model.addObserver(this);
		super.setText( format.format(model.getActivation()) );
	}
	
	public void setStartPoint( double x, double y ) {
		setBounds( new Point2D.Double(x,y), new Point2D.Double(x+DEFAULT_WIDTH, y+DEFAULT_HEIGHT));
	}
	
	public void setText( String s ) {
		super.setText(s);
		if ( model != null )
			model.setWeight(Double.parseDouble(s));
	}
	
	public void update( Observable obs, Object o ) {
		super.setText( weightDisplayed ? format.format(model.getActivation()) + "\n" + format.format(model.getWeight())
				: format.format(model.getActivation()));
	}
	
	protected void initNumberFormat() {
		format = NumberFormat.getInstance();
		format.setMaximumFractionDigits(2);
		format.setMinimumFractionDigits(2);
	}
}
